﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSE.Tools.SchemaComparer.Extractor;
using System.Diagnostics;

namespace PSE.Tools.SchemaComparer.Comparer
{
    public abstract class ScriptObjectComparer : DBObjectComparer<ScriptObject>
    {
        protected override DBObjectCompareResult Compare(ScriptObject sourceObject, ScriptObject targetObject)
        {
            DBObjectCompareResult result = new DBObjectCompareResult();
            result.ObjectName = sourceObject.Name;

            if (sourceObject.ObjectType != targetObject.ObjectType)
                result.PropertyCompareResults.Add(new PropertyCompareResult()
                {
                    PropertyName = "OBJECT_TYPE",
                    SourceValue = sourceObject.ObjectType,
                    TargetValue = targetObject.ObjectType,
                });

            if (sourceObject.BodyLength != targetObject.BodyLength)
                result.PropertyCompareResults.Add(new PropertyCompareResult()
                {
                    PropertyName = "BODY_LENGTH",
                    SourceValue = sourceObject.BodyLength,
                    TargetValue = targetObject.BodyLength,
                });

            if (sourceObject.Body != targetObject.Body)
            {
                result.PropertyCompareResults.Add(new PropertyCompareResult()
                {
                    PropertyName = "BODY",
                    SourceValue = sourceObject.Body,
                    TargetValue = targetObject.Body,
                });

                ///Solucao de contorno para o problema na recuperacao de procedures internas do pacote (procedures nao definidas no header)
                int sourceProcCount, sourceFunctionCount, targetProcCount, targetFunctionCount;
                sourceProcCount = sourceObject.Body.CountWordsOcurrence("PROCEDURE ");
                sourceFunctionCount = sourceObject.Body.CountWordsOcurrence("FUNCTION ");
                string sourceObjects = null;
                if ((sourceProcCount + sourceFunctionCount) > 1)
                {
                    sourceObjects = GetObjectsNames(sourceObject.Body);
                }

                targetProcCount = targetObject.Body.CountWordsOcurrence("PROCEDURE ");
                targetFunctionCount = targetObject.Body.CountWordsOcurrence("FUNCTION ");
                string targetObjects = null;
                if ((targetProcCount + targetFunctionCount) > 1)
                {
                    targetObjects = GetObjectsNames(targetObject.Body);
                }

                if (!string.IsNullOrEmpty(sourceObjects) && !string.IsNullOrEmpty(targetObjects))
                {
                    result.PropertyCompareResults.Add(new PropertyCompareResult()
                    {
                        PropertyName = "Procedures e Functions que podem apresentar divergências",
                        SourceValue = sourceObjects,
                        TargetValue = targetObjects,
                    });

                    result.ObjectName = "Clique para maiores detalhes";
                }
                ///Fim solucao de contorno

            }

            if (result.PropertyCompareResults.Count > 0)
                result.CompareStatus = DBObjectCompareStatus.ObjectHasDiferences;
            else//se nao houver divergencias, retornar nulo
                result = null;


            return result;
        }

        private string GetObjectsNames(string body)
        {
            string tempBody = body.ToUpper().Replace("\r\n", "  ").Replace("(", " ").Replace("\t", " ").Replace("FUNCTION", "PROCEDURE");

            int index = tempBody.IndexOf("PROCEDURE");
            List<string> procs = new List<string>();
            string word;
            while (index >= 0)
            {
                word = GetWord(tempBody.Substring(index + 9));
                procs.Add(word);
                index = tempBody.IndexOf("PROCEDURE", index + 9);
            }

            procs.Sort();

            StringBuilder ret = new StringBuilder();
            for (int i = 0; i < procs.Count; i++)
            {
                ret.AppendLine("- " + procs[i]);
            }

            return ret.ToString();
        }

        private string GetWord(string packageBody)
        {
            string[] words = packageBody.Split(' ');
            for (int i = 0; i < words.Length; i++)
            {
                if (words[i] != string.Empty)
                    return words[i];
            }

            return string.Empty;
        }
    }
}
